<!doctype html>
<html>
		<head>
		<title>Demo</title>
		<style>
body {
	background-color: grey;
}
canvas {
	background-color: white;
}
</style>
<script id="shader-vs" type="x-shader/x-vertex">
	uniform mat4 uMVMatrix;
	uniform mat4 uPMatrix;

	attribute vec3 aVertexPosition;
	attribute vec4 aVertexColor;
	attribute vec3 aVertexNormal;

	varying highp vec4 vColor;
	varying highp vec3 vPosition;
	varying highp vec3 N;

	void main(void) {
		gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
        
        vColor = aVertexColor;
        vPosition = aVertexPosition;
		N = aVertexNormal; 		
	}
</script>
<script id="shader-fs" type="x-shader/x-fragment">
	uniform highp mat3 uNormalMatrix;
	uniform highp mat4 uMVMatrix;
	uniform highp mat4 uPMatrix;

	varying highp vec4 vColor;
	varying highp vec3 vPosition;
	varying highp vec3 N;

	void main(void) {
        highp vec3 pointLightPosition = vec3(-1.0,3.0,1.0);

        highp vec3 pointLightDirection = vec3(pointLightPosition.xyz - vPosition.xyz);

		highp mat4 mvp = uPMatrix * uMVMatrix;

        highp vec3 L = vec3(mvp * vec4(pointLightDirection, 1.0));
		highp vec3 V = -vec3(mvp * vec4(vPosition,1.0));

   		highp vec3 l = normalize(L);
    	highp vec3 n = normalize(uNormalMatrix * N);
    	highp vec3 v = normalize(V);
		
		highp vec3 R = reflect(l, n);

		highp float diffuseLambert = dot(l,n);
		highp float Roughness = 1.0;
		highp float AmbientIntensity = 0.3;
		highp vec3 DiffuseLightIntensity = vec3(0.9, 0.9, 0.9);
		highp float SpecularIntensity = 0.5;
		highp float shininess = 128.0;

		highp float specular = pow( max(0.0,dot(R,v)), shininess);

		highp vec3 AmbientColour = vec3(0.1, 0.1, 0.1);
		highp vec3 DiffuseMaterialColour = vColor.xyz;
		highp vec3 SpecularColour = vec3(1.0, 1.0, 1.0);
    
	    gl_FragColor = vec4(AmbientColour*AmbientIntensity + 
                        diffuseLambert * DiffuseMaterialColour*DiffuseLightIntensity +
                        SpecularColour * specular*SpecularIntensity, vColor.a);
	}
</script>
<script src="libs/jquery.min.js"></script>
<script src="libs/raf_polyfill.js"></script>
<script src="libs/gl-matrix-min.js"></script>
<script src="libs/webgl-debug.js"></script>
<script src="libs/vector3.js"></script>
<script src="libs/sphere_mesh.js"></script>
<script src="libs/plane_mesh.js"></script>
<script src="libs/SphereObject.js"></script>
<script>
	var gl = null,
		canvas = null,
		glProgram = null,
		fragmentShader = null,
		vertexShader = null;
		
	var vertexPositionAttribute = null,
		vertexNormalAttribute = null,
		vertexColorAttribute = null,
		trianglesVerticeBuffers = [],
		trianglesNormalBuffers = [],
		trianglesColorBuffers = [],
		vertexIndexBuffers = [];

	var sceneElements = []; 
	var GROUND_Y = -1.0;
	var RECTANGLE_LENGTH = 4.0;

	//mouse events	
	var capture = false;
	var start = 0;
	var zoom = 0.2;
	
	var angleX = 0.0,
		angleY = 0.0;

	var mvMatrix = mat4.create(),
		pMatrix = mat4.create(),
		normalMatrix = mat3.create();

	var ELASTICITY =  -0.8;	
	var angle = 0.0;
	var speed = 0.0;
	var paused = false;
	var fire = false;
	
	var life = 3;
	var score = 0;
	
	var targetX = 0.0,
		targetY = 0.0,
		targetZ = 0.0;
		
	function initWebGL()
	{
		canvas = document.getElementById("my-canvas");  
		try{
			gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");					
	//		gl = canvas.getContext("webgl",  {preserveDrawingBuffer: true}) || canvas.getContext("experimental-webgl",  {preserveDrawingBuffer: true});					
		}catch(e){
		}
						
		if(gl)
		{
			gl = WebGLDebugUtils.makeDebugContext(gl);
			initShaders();
			setupPlaneMesh(0, {	"translation": [0.0, GROUND_Y, 0.0]} );
			setupPlaneMesh(1, {	"translation": [0.0, GROUND_Y, 0.0], "size": 10} );
			addBox(2);
			var radius = 1.0;
			var s = new SphereObject( {	"vbo_index": 3, 
										"radius": radius,
										"position": new Vector3(0.0, 0.0, 0.0), 
										"velocity": new Vector3(0.0, 0.0, 0.0), 
										"acceleration": new Vector3(0.0, -0.01, 0.0)															
										});
			sceneElements.push(s);
			setupSphereMesh(3, {"color": [1.0, 0.0, 0.0, 0.9], "radius":radius }	);
			getMatrixUniforms();					

			vertexPositionAttribute = gl.getAttribLocation(glProgram, "aVertexPosition");
			vertexColorAttribute = gl.getAttribLocation(glProgram, "aVertexColor");
			vertexNormalAttribute = gl.getAttribLocation(glProgram, "aVertexNormal");
			gl.enableVertexAttribArray(vertexPositionAttribute);
			gl.enableVertexAttribArray(vertexColorAttribute);
			gl.enableVertexAttribArray(vertexNormalAttribute);
			
			gl.viewport(0, 0, canvas.width, canvas.height);
			mat4.perspective(45, canvas.width / canvas.height, 0.1, 100.0, pMatrix);
			gl.uniformMatrix4fv(glProgram.pMatrixUniform, false, pMatrix);
			
			setNewTargetPosition();
			(function animLoop(){
				if( !paused ){	
					setupWebGL();
					drawScene(); 
				}
				showInfo();
				requestAnimationFrame(animLoop, canvas);
			})();
		}else{	
			alert(  "Error: Your browser does not appear to support WebGL.");
		}
	}
	
	function showInfo(){
//		$('#position').html('(' + sceneElements[0].position.x + ',' + sceneElements[0].position.y + ',' + sceneElements[0].position.z + ')');
//		$('#life').html(life);
		$('#score').html(score);
		$('#angle').html(angle);
		$('#target').html('(' + targetX + ',' + targetY + ',' + targetZ + ')');
	}
	
	function setupWebGL()
	{
		//set the clear color to a shade of green
		gl.clearColor(0.5, 0.5, 0.5, 1.0); 	
		gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 	
		gl.enable(gl.DEPTH_TEST);
	}
	
	function initShaders()
	{
		vertexShader = makeShader($('#shader-vs').html(), gl.VERTEX_SHADER);
		fragmentShader = makeShader($('#shader-fs').html(), gl.FRAGMENT_SHADER);
		
		//create program
		glProgram = gl.createProgram();
		
		//attach and link shaders to the program
		gl.attachShader(glProgram, vertexShader);
		gl.attachShader(glProgram, fragmentShader);
		gl.linkProgram(glProgram);

		if (!gl.getProgramParameter(glProgram, gl.LINK_STATUS)) {
			alert("Unable to initialize the shader program.");
		}
		
		//use program
		gl.useProgram(glProgram);
	}
	
	function makeShader(src, type)
	{
		//compile the vertex shader
		var shader = gl.createShader(type);
		gl.shaderSource(shader, src);
		gl.compileShader(shader);

		if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
			alert("Error compiling shader: " + gl.getShaderInfoLog(shader));
		}
		return shader;
	}
	
	function searchForObject(arr, index)
	{
		for(var i in arr)
		{
			if(arr[i].vbo_index == index)
			{
				return i;
			}	
		}
		return -1;
	}

	function isAboveGround(n)
	{
		return (INITIAL_HEIGHT_TRANSLATION_OF_SPHERES - (sceneElements[n].position.y + sceneElements[n].radius) > GROUND_Y);
	}
	
	angle = 14;
	function checkForCollision(){
		var DISTANCE = 2.0;
		var p1 = new Vector3(targetX, targetY, targetZ); // wall
		var p2 = sceneElements[0].position;// + sceneElements[0].velocity; //ball
		
		var v = new Vector3( p1.x - p2.x, p1.y - p2.y, p1.z - p2.z);
		var len = v.length()
//		console.log('len:' + len);
		if(len < DISTANCE)
		{
			fire = false;
			alert('Hit. You got score');
			score++;
			setNewTargetPosition();
		}
	}
	
	function setNewTargetPosition(){
		targetX = Math.random() * 15 + 20.0;
		targetY = Math.random() * 10 + 10.0;
		targetZ = Math.random() * 0.0;
		//targetX = 10.0;
		//targetY = 10.0;
		//targetZ = 30;
	}
	
	var PLANE_X = -10.0;
	var PLANE_Y = -1.0;
	var PLANE_Z = -30.0;
	var MAX_VELOCITY = 5.0;
	
	function drawScene()
	{
		for(var i=0; i < vertexIndexBuffers.length; ++i)
		{
			mat4.identity(mvMatrix);
			mat4.translate(mvMatrix, [PLANE_X, PLANE_Y, PLANE_Z]);              		
			mat4.rotate(mvMatrix, angleX*2*Math.PI/180.0, [0.0, 1.0, 0.0]);              
			mat4.rotate(mvMatrix, angleY*2*Math.PI/180.0, [1.0, 0.0, 0.0]);              
			mat4.scale(mvMatrix, [zoom, zoom, zoom]);              		
			//individual transforms			
			if( i==2 )//canon
			{
				mat4.translate(mvMatrix, [-RECTANGLE_LENGTH*.1,3.0, 0.0]);     
				mat4.rotate(mvMatrix, angle*.1, [0.0, 0.0, 1.3]);     				
			}else if( i==0)//plane
			{
				mat4.rotate(mvMatrix, -0.3, [-0.3, 0.0, 0.2]);              
				mat4.rotate(mvMatrix, 90, [0.0, 1.0, 0.0]);     
			}else if(i==3){//projectile
				mat4.translate(mvMatrix, [
					sceneElements[0].position.x + Math.cos(angle*.1), 
					sceneElements[0].position.y + 3.0 + sceneElements[0].radius+Math.sin(angle*.1),
					sceneElements[0].position.z + 0.0]
					);    
				if(fire){
					sceneElements[0].velocity.y += sceneElements[0].acceleration.y; 
					if (sceneElements[0].velocity.y > MAX_VELOCITY) sceneElements[0].velocity.y = MAX_VELOCITY;
					
					sceneElements[0].position.x += sceneElements[0].velocity.x;
					sceneElements[0].position.y += sceneElements[0].velocity.y;
					sceneElements[0].position.z += sceneElements[0].velocity.z;
					
					checkForCollision();
				}						
			} else if (i == 1){//target
				mat4.translate(mvMatrix, [targetX, targetY, targetZ]);
				mat4.rotate(mvMatrix, -0.3, [-0.3, 0.0, 0.2]);
				mat4.rotate(mvMatrix, 90, [0.0, 1.0, 0.0]); 
			}

			mat4.toInverseMat3(mvMatrix, normalMatrix);
			mat3.transpose(normalMatrix);
			setMatrixUniforms();

			gl.bindBuffer(gl.ARRAY_BUFFER, trianglesVerticeBuffers[i]);
			gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);

			if(i==2){
			  gl.disableVertexAttribArray(vertexColorAttribute);
			  gl.vertexAttrib4f(vertexColorAttribute, 1.0, 0.9, 0.7, 1.0);
			}else{
				gl.enableVertexAttribArray(vertexColorAttribute);						              
				gl.bindBuffer(gl.ARRAY_BUFFER, trianglesColorBuffers[i]);
				gl.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0);
			}
			gl.bindBuffer(gl.ARRAY_BUFFER, trianglesNormalBuffers[i]);
			gl.vertexAttribPointer(vertexNormalAttribute, 3, gl.FLOAT, false, 0, 0);
			
			gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexIndexBuffers[i]);
			gl.drawElements(gl.TRIANGLES, vertexIndexBuffers[i].numItems, gl.UNSIGNED_SHORT, 0);
		}
	}
	
	function getMatrixUniforms(){
		glProgram.pMatrixUniform = gl.getUniformLocation(glProgram, "uPMatrix");
		glProgram.mvMatrixUniform = gl.getUniformLocation(glProgram, "uMVMatrix");          
		glProgram.normalMatrixUniform = gl.getUniformLocation(glProgram, "uNormalMatrix");          
	}
	
	function setMatrixUniforms() {       
		gl.uniformMatrix4fv(glProgram.mvMatrixUniform, false, mvMatrix);
		gl.uniformMatrix3fv(glProgram.normalMatrixUniform, false, normalMatrix);
	}

	function addBox(n)
	{
		var colorData = [];
		//8 vertices
		var vertexPositionData = [
			//0-3
			0,0,0,		
			RECTANGLE_LENGTH,0,0,
			RECTANGLE_LENGTH,RECTANGLE_LENGTH*.5,0,
			0,RECTANGLE_LENGTH*.5,0,		
			
			//4-7
			0,0,RECTANGLE_LENGTH*.5,		
			RECTANGLE_LENGTH,0,RECTANGLE_LENGTH*.5,
			RECTANGLE_LENGTH,RECTANGLE_LENGTH*.5,RECTANGLE_LENGTH*.5,
			0,RECTANGLE_LENGTH*.5,RECTANGLE_LENGTH*.5,		
		];

		//10 triangles, 2 per face, 1 face not drawn
		var indexData = [
			0,1,2,	//front
			0,2,3,

			0,3,7,	//left
			0,7,4,

			2,7,3,	//top
			2,6,7,

			4,6,5,	//back
			4,7,6,

			1,0,4,	//bottom
			1,4,5,
		];

	  normalData = calculateNormals(vertexPositionData, indexData);

	  trianglesNormalBuffers[n] = gl.createBuffer();
	  gl.bindBuffer(gl.ARRAY_BUFFER, trianglesNormalBuffers[n]);
	  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normalData), gl.STATIC_DRAW);
	  trianglesNormalBuffers[n].itemSize = 3;
	  trianglesNormalBuffers[n].numItems = normalData.length / 3;

	  trianglesVerticeBuffers[n] = gl.createBuffer();
	  gl.bindBuffer(gl.ARRAY_BUFFER, trianglesVerticeBuffers[n]);
	  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexPositionData), gl.STATIC_DRAW);
	  trianglesVerticeBuffers[n].itemSize = 3;
	  trianglesVerticeBuffers[n].numItems = vertexPositionData.length / 3;
	 

	  vertexIndexBuffers[n] = gl.createBuffer();
	  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexIndexBuffers[n]);
	  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexData), gl.STREAM_DRAW);
	  vertexIndexBuffers[n].itemSize = 3;
	  vertexIndexBuffers[n].numItems = indexData.length;
	}

	function calculateNormals(vertices, indices)
	{
		var normals = [];
		for(var i=0; i<indices.length; i+=3)
			{
				var a = indices[i];
				var b = indices[i + 1];
				var c = indices[i + 2];
	
				//normal is the cross product
				var v1 = [
							vertices[a*3] - vertices[b*3],
							vertices[a*3 + 1] - vertices[b*3 + 1],
							vertices[a*3 + 2] - vertices[b*3 + 2]
						];
				var v2 = [
							vertices[a*3] - vertices[c*3],
							vertices[a*3 + 1] - vertices[c*3 + 1],
							vertices[a*3 + 2] - vertices[c*3 + 2]
					];
	
				var cross = [
					v1[1]*v2[2] - v1[0]*v2[1],
					v1[2]*v2[0] - v1[0]*v2[2],
					v1[0]*v2[1] - v1[1]*v2[0]
				];	
				//same value for each of the three vertices
				normals.push.apply(normals, cross);
				normals.push.apply(normals, cross);
				normals.push.apply(normals, cross);
			}	
			return normals;
	}
	
	function adjustZoom(delta)
	{
		if(delta > 0)
		{
			zoom += 0.1;
		}else{
			zoom -= 0.1;
			if(zoom < 0.01){
				zoom = 0.1;
			}
		}
	}
	
	$(document).keyup(function(evt){
		switch(evt.keyCode){
			case 80: //'p'
				paused =!paused;
				break;	                
			case 83: //'s'
				--angle;
				break;
			case 68: //'d' 
				++angle;
				break;
			case 65: //'a'
				speed -= 5.0;
				break;
			case 87: //'w'
				speed += 5.0;
				break;
			case 70:
				fire = true;
				console.log("fire!");
				sceneElements[0].position = new Vector3(0.0, 0.0, 0.0);
				sceneElements[0].velocity = new Vector3(Math.cos(angle*.1), Math.sin(angle*.1), 0.0);
				break;	
			default:
				console.log(evt.keyCode);
				break;    
	
		}    	
	});	  
		
	$(document).ready(function(evt){
		$("#my-canvas").on("mousewheel", function (e){
			adjustZoom(window.event.wheelDelta);
		}).on("DOMMouseScroll", function (e){
			adjustZoom(e.originalEvent.detail * -1.0);
		});
	
		$("#my-canvas").on("mousedown", function (e){
			 capture = true;
			 start = [e.pageX, e.pageY]; //0 to 500
			 console.log("start:" + start);
		});
	
		$("#my-canvas").on("mouseup", function (e){
			 capture = false;
			 console.log("end capture");
		});
	
		 $("#my-canvas").mousemove(function(e) {
			if(capture)
			{
				var x = (e.pageX - start[0]);
				var y = (e.pageY - start[1]);
				start[0] = e.pageX;
				start[1] = e.pageY;
	
				angleX += x;
				angleY += y;
			//	console.log("Angle: (" + angleX + "," + angleY + ")");
			}
		 });
	
	});
</script>
</head>
<body onload="initWebGL()">
  <canvas id="my-canvas" width="500" height="500"> Your browser does not support the HTML5 canvas element. </canvas>
<div>
<table width="200" border="1">
  <tr>
    <td>Angle</td>
    <td><p id='angle'></p></td>
  </tr>
  <tr>
    <td>Target</td>
    <td><p id='target'></p></td>
  </tr>
  <tr>
    <td>Score</td>
    <td><p id='score'></p></td>
  </tr>
</table>
</div>
</body>
</html>
